﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;


namespace Deployment.Data.Variable
{
    [XmlRoot("Variable")]
    [Serializable()]
    public abstract class AbstractVariable : ContentCheckingNotifyPropertyChanged
    {
        private string _variableName;
        private string _value;
        private string _extra;
        private string _environment;
        private Environment.EnvironmentsFile _environments;
        private string _typeDescription;

        public static List<AbstractVariable> getAvailableVariableTypes()
        {
            List<AbstractVariable> varTypes = new List<AbstractVariable>();
            Assembly asm = Assembly.GetExecutingAssembly();
            FileInfo assemblyFile = new FileInfo(asm.Location);
            DirectoryInfo di = assemblyFile.Directory;
            FileInfo[] files = di.GetFiles("*.dll", SearchOption.AllDirectories);
            foreach (FileInfo file in files)
            {
                try
                {
                    Assembly asmFile = Assembly.LoadFrom(file.FullName);
                    Type[] types = asmFile.GetTypes();
                    for (int i = 0; i < types.Length; i++)
                    {
                        if (types[i].IsSubclassOf(typeof(AbstractVariable)) && !types[i].IsAbstract)
                        {
                            
                            AbstractVariable obj = asmFile.CreateInstance(types[i].FullName) as AbstractVariable;
                            if (obj != null)
                                varTypes.Add(obj);
                        }
                    }
                }
                catch (Exception) { }
            }
            return varTypes;
        }

        public AbstractVariable(Environment.EnvironmentsFile environmentsFile = null)
        {
            this.EnvironmentsFile = environmentsFile;
            base.PropertyChanged += AbstractVariable_PropertyChanged;
            _typeDescription = getTypeDescriptionName();
        }

        void AbstractVariable_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Equals("DeploymentValue") | e.PropertyName.Equals("isContentOk"))
                return;
            
            OnPropertyChanged("DeploymentValue");
            OnPropertyChanged("isContentOk");
        }

        [XmlAttribute]
        public string Name
        {
            get { return _variableName; }
            set
            {
                if (_variableName != value)
                {
                    _variableName = value;
                    OnPropertyChanged("Name");
                }
            }
        }

        [XmlElement]
        public string Value
        {
            get { return _value; }
            set
            {
                if (_value != value)
                {
                    _value = value;
                    OnPropertyChanged("Value");
                }
            }
        }

        [XmlElement]
        public string Extra
        {
            get { return _extra; }
            set
            {
                if (_extra != value)
                {
                    _extra = value;
                    OnPropertyChanged("Extra");
                }
            }
        }

        [XmlAttribute]
        public string EnvironmentName
        {
            get { return _environment; }
            set
            {
                if (_environment != value)
                {
                    _environment = value;
                    OnPropertyChanged("EnvironmentName");
                    OnPropertyChanged("Environment");
                }
            }
        }

        [XmlIgnore]
        public Environment.EnvironmentsFile EnvironmentsFile
        {
            get { return _environments; }
            set
            {
                _environments = value;
                OnPropertyChanged("EnvironmentsFile");
                OnPropertyChanged("Environment");
            }
        }

        [XmlIgnore]
        public Environment.Environment Environment
        {
            get
            {
                if (_environments != null && !string.IsNullOrEmpty(EnvironmentName))
                    return _environments.get(EnvironmentName);
                
                return null;
            }
        }

        [XmlIgnore]
        public string DeploymentValue
        {
            get { return calculateValue(); }
        }

        [XmlIgnore]
        public string TypeDescription
        {
            get { return _typeDescription; }
        }

        

        private AbstractVariableEditorControl _editorControl;
        [XmlIgnore]
        public AbstractVariableEditorControl EditorControl
        {
            get
            {
                if (_editorControl == null)
                {
                    _editorControl = createControl();
                    _editorControl.Variable = this;
                    _editorControl.Unloaded += _editorControl_Unloaded;
                }
                return _editorControl;
            }
        }

        void _editorControl_Unloaded(object sender, System.Windows.RoutedEventArgs e)
        {
            _editorControl = null;
        }
        

        protected internal abstract string calculateValue();

        //protected internal abstract void ReadUnhandledSubElement(XmlReader reader);

        //protected internal abstract void WriteExtraElementData(XmlWriter writer);

        protected internal abstract string getTypeDescriptionName();

        

        protected virtual internal AbstractVariableEditorControl createControl()
        {
            return new AbstractVariableEditorControl();
        }

        
    }
}
